package cn.slipi.admin.common.utils;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * http 请求可配ssh及代理
 * 设置代理本地测试时用:configBuilder.setProxy(new HttpHost("10.59.74.70", 80));
 *
 * @author lee
 */
public class HttpUtil {
    private static final PoolingHttpClientConnectionManager connMgr;
    private static final RequestConfig requestConfig;
    private static final int MAX_TIMEOUT = 7000;
    private static final String PIX_HTTPS = "https";

    private static final Logger LOG = LoggerFactory.getLogger(HttpUtil.class);

    static {
        // 设置连接池
        connMgr = new PoolingHttpClientConnectionManager();
        // 设置连接池大小
        connMgr.setMaxTotal(100);
        connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());
        connMgr.setValidateAfterInactivity(1000);
        RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 设置连接超时
        configBuilder.setConnectTimeout(MAX_TIMEOUT);
        // 设置读取超时
        configBuilder.setSocketTimeout(MAX_TIMEOUT);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);

        requestConfig = configBuilder.build();
    }

    /**
     * 发送 GET 请求（HTTP），K-V形式
     *
     * @param url
     * @param headers
     * @return
     */
    public static String doGet(String url, Map<String, Object> headers) throws Exception {
        String apiUrl = url;
        String result = null;
        CloseableHttpClient httpClient;
        if (apiUrl.startsWith(PIX_HTTPS)) {
            httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory())
                    .setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
        } else {
            httpClient = HttpClients.createDefault();
        }
        try {
            HttpGet httpGet = new HttpGet(apiUrl);
            for (String key : headers.keySet()) {
                httpGet.setHeader(key, headers.get(key).toString());
            }
            HttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream inputStream = entity.getContent();
                result = IOUtils.toString(inputStream, "UTF-8");
            }
        } catch (IOException e) {
            LOG.warn("HttpUtil网络连接异常:{} {}", e.getCause().getClass());
            throw new RuntimeException(MessageFormat.format("HttpUtil网络连接异常:{0}", e.getMessage()), e);
        }
        return result;
    }

    /**
     * 发送 GET 请求（HTTP），K-V形式
     *
     * @param url
     * @param headers
     * @param params
     * @return
     */
    private static String doGet(String url, Map<String, Object> headers, Map<String, Object> params) throws Exception {
        String apiUrl = url;
        StringBuffer param = new StringBuffer();
        int i = 0;
        for (String key : params.keySet()) {
            if (i == 0) {
                param.append("?");
            } else {
                param.append("&");
            }
            param.append(key).append("=").append(URLEncoder.encode(params.get(key).toString(), "utf-8"));
            i++;
        }
        apiUrl += param;
        String result = null;
        CloseableHttpClient httpClient;
        if (apiUrl.startsWith(PIX_HTTPS)) {
            httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory())
                    .setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
        } else {
            httpClient = HttpClients.createDefault();
        }
        try {
            HttpGet httpGet = new HttpGet(apiUrl);
            for (String key : headers.keySet()) {
                httpGet.setHeader(key, headers.get(key).toString());
            }
            HttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream inputStream = entity.getContent();
                result = IOUtils.toString(inputStream, "UTF-8");
            }
        } catch (IOException e) {
            LOG.warn("HttpUtil网络连接异常:{} {}", e.getCause().getClass());
            throw new RuntimeException(MessageFormat.format("HttpUtil网络连接异常:{0}", e.getMessage()), e);
        }
        return result;
    }

    /**
     * 发送 POST 请求，K-V形式
     *
     * @param apiUrl
     * @param headers
     * @param params
     * @return
     */
    public static String doPost(String apiUrl, Map<String, Object> headers, Map<String, Object> params) throws Exception {
        CloseableHttpClient httpClient = getClient(apiUrl);
        String httpStr;
        HttpPost httpPost = new HttpPost(apiUrl);
        for (String key : headers.keySet()) {
            httpPost.setHeader(key, headers.get(key).toString());
        }
        CloseableHttpResponse response = null;
        try {
            httpPost.setConfig(requestConfig);
            List<NameValuePair> pairList = new ArrayList<>(params.size());
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                if (entry.getKey() == null || entry.getValue() == null) {
                    continue;
                }
                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
                pairList.add(pair);
            }
            httpPost.setEntity(new UrlEncodedFormEntity(pairList, StandardCharsets.UTF_8));
            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            httpStr = EntityUtils.toString(entity, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
            LOG.warn("HttpUtil网络连接异常:{} {}", apiUrl, e.getCause().getClass());
            throw new Exception("HttpUtil网络连接异常,请稍后在试");
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                    LOG.warn("HttpUtil网络连接异常:{} {}", apiUrl, e.getCause().getClass());
                    throw new Exception("HttpUtil网络连接异常,请稍后在试");
                }
            }
        }
        return httpStr;
    }

    /**
     * 发送 POST 请求，K-V形式
     *
     * @param apiUrl
     * @param headers
     * @param param
     * @return
     */
    public static String doPost(String apiUrl, Map<String, Object> headers, String param) throws Exception {
        CloseableHttpClient httpClient = getClient(apiUrl);
        String httpStr;
        HttpPost httpPost = new HttpPost(apiUrl);
        for (String key : headers.keySet()) {
            httpPost.setHeader(key, headers.get(key).toString());
        }
        CloseableHttpResponse response = null;
        try {
            httpPost.setConfig(requestConfig);
            StringEntity stringEntity = new StringEntity(param);
            httpPost.setEntity(stringEntity);
            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            httpStr = EntityUtils.toString(entity, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
            LOG.warn("HttpUtil网络连接异常:{} {}", apiUrl, e.getCause().getClass());
            throw new Exception("HttpUtil网络连接异常,请稍后在试");
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {
                    e.printStackTrace();
                    LOG.warn("HttpUtil网络连接异常:{} {}", apiUrl, e.getCause().getClass());
                    throw new Exception("HttpUtil网络连接异常,请稍后在试");
                }
            }
        }
        return httpStr;
    }

    /**
     * 发送 POST 请求，JSON形式
     *
     * @param apiUrl
     * @param json
     * @return
     */
    public static String doPost(String apiUrl, JSONObject json) throws Exception {
        CloseableHttpClient httpClient = getClient(apiUrl);
        String httpStr;
        HttpPost httpPost = new HttpPost(apiUrl);
        CloseableHttpResponse response = null;
        try {
            httpPost.setConfig(requestConfig);
            // 解决中文乱码问题
            StringEntity stringEntity = new StringEntity(json.toString(), "UTF-8");
            stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("application/json");
            httpPost.setEntity(stringEntity);
            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            httpStr = EntityUtils.toString(entity, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
            LOG.warn("HttpUtil网络连接异常:{} {}", apiUrl, e.getCause().getClass());
            throw new Exception("HttpUtil网络连接异常,请稍后在试");
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (Exception e) {
                    e.printStackTrace();
                    LOG.warn("HttpUtil网络连接异常:{} {}", apiUrl, e.getCause().getClass());
                    throw new Exception("HttpUtil网络连接异常,请稍后在试");
                }
            }
        }
        return httpStr;
    }

    private static CloseableHttpClient getClient(String url) throws Exception {
        CloseableHttpClient httpClient;
        if (url.startsWith(PIX_HTTPS)) {
            httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory())
                    .setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build();
        } else {
            httpClient = HttpClients.createDefault();
        }
        return httpClient;
    }

    /**
     * 创建SSL安全连接
     *
     * @return
     */
    private static SSLConnectionSocketFactory createSSLConnSocketFactory() throws Exception {
        SSLConnectionSocketFactory sslConnectionSocketFactory = null;
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true).build();
            sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, (arg0, arg1) -> true);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            LOG.warn("SSL安全连接创建失败:{}", e.getCause().getClass());
            throw new Exception("SSL安全连接创建失败,请稍后在试");
        }
        return sslConnectionSocketFactory;
    }
}
